package com.lhkj.ct.meta.modules.recycle.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lhkj.ct.base.enums.DeleteStatus;
import com.lhkj.ct.base.model.dto.PageQuery;
import com.lhkj.ct.base.mybatis.IBaseEntity;
import com.lhkj.ct.base.spring.SpringContextHolder;
import com.lhkj.ct.base.utils.LambdaUtils;
import com.lhkj.ct.base.utils.ShiroUtil;
import com.lhkj.ct.meta.modules.gauge.mapper.ScaleMapper;
import com.lhkj.ct.meta.modules.gauge.model.entity.TblScale;
import com.lhkj.ct.meta.modules.patient.mapper.PatientMapper;
import com.lhkj.ct.meta.modules.patient.model.entity.TblPatient;
import com.lhkj.ct.meta.modules.psychology.mapper.ScaleReportMapper;
import com.lhkj.ct.meta.modules.psychology.model.entity.TblScaleReport;
import com.lhkj.ct.meta.modules.recycle.entity.TblRecycleBin;
import com.lhkj.ct.meta.modules.recycle.mapper.RecycleBinMapper;
import com.lhkj.ct.meta.modules.recycle.service.RecycleBinService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jobob
 * @since 2023-10-09
 */
@Service
public class RecycleBinServiceImpl implements RecycleBinService {

    @Resource
    private RecycleBinMapper recycleBinMapper;

    @Override
    public IPage<TblRecycleBin> selectRecyclePage(TblRecycleBin recycleBin, PageQuery pageQuery) {
        LambdaQueryWrapper<TblRecycleBin> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(recycleBin.getTitle()), TblRecycleBin::getTitle, recycleBin.getTitle());
        wrapper.like(StringUtils.isNotBlank(recycleBin.getOperator()), TblRecycleBin::getOperator, recycleBin.getOperator());
        wrapper.eq(Objects.nonNull(recycleBin.getSourceType()), TblRecycleBin::getSourceType, recycleBin.getSourceType());
        Page<TblRecycleBin> page = generatePage(pageQuery);
        return recycleBinMapper.selectPage(page, wrapper);
    }

    @Override
    public <T> int logicDelete(Collection<T> ids, Function<T, Integer> function) {
        if (ids.size() == 1) {
            return function.apply(new ArrayList<T>(ids).get(0));
        }
        int count = 0;
        List<CompletableFuture<Integer>> futures = new ArrayList<>();
        for (T id : ids) {
            CompletableFuture<Integer> e = CompletableFuture.supplyAsync(() -> {
                try {
                    return function.apply(id);
                } catch (Exception ex) {
                    return 0;
                }
            });
            futures.add(e);
        }
        //等待全部完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        //获取内容
        for (CompletableFuture<Integer> future : futures) {
            try {
                count += future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        return count;
    }

    @Override
    public <T extends IBaseEntity<String>> int logicDeleteRealSource(BaseMapper<T> dao,
                                                                     String sourceId,
                                                                     SFunction<T, ?> idFunc,
                                                                     SFunction<T, ?> sFunction,
                                                                     Object delV,
                                                                     TblRecycleBin recycleBin) {
        recycleBin.setOperator(ShiroUtil.getAuthUserInfo().getUserName());
        recycleBin.setOptime(LocalDateTime.now());
        recycleBinMapper.insert(recycleBin);
        UpdateWrapper<T> wrapper = new UpdateWrapper<>();
        wrapper.set(LambdaUtils.getUnderLineName(sFunction), delV);
        wrapper.lambda().eq(idFunc, sourceId);
        return dao.update(null, wrapper);
    }

    @Override
    public int reverse(String recycleId) {
        TblRecycleBin target = recycleBinMapper.selectById(recycleId);
        if (null == target) {
            return 0;
        }
        boolean handleRes;
        switch (target.getSourceType()) {
            case PATIENT:
                handleRes = handleProcess(target.getSourceId(), TblPatient::getDelFlag, (PatientMapper)SpringContextHolder.getBean(target.getSourceType().getMapper())) > 0;
                break;
            case SCALE:
                handleRes = handleProcess(target.getSourceId(), TblScale::getDelFlag, (ScaleMapper)SpringContextHolder.getBean(target.getSourceType().getMapper())) > 0;
                break;
            case SCALE_REPORT:
                handleRes = handleProcess(target.getSourceId(), TblScaleReport::getDelFlag, (ScaleReportMapper)SpringContextHolder.getBean(target.getSourceType().getMapper())) > 0;
                break;
//            case GAUGE:
//                handleRes = handleProcess(target.getCZBH(), LBEntity::getSCZT, ApplicationContextHelper.getBean(target.getLY().getMapper())) > 0;
//                break;
//            case QUESTIONNAIRE:
//                handleRes = handleProcess(target.getCZBH(), WJEntity::getSCZT, ApplicationContextHelper.getBean(target.getLY().getMapper())) > 0;
//                break;
//            case ANSWER_RECORD:
//                handleRes = handleProcess(target.getCZBH(), WJJGEntity::getSCZT, ApplicationContextHelper.getBean(target.getLY().getMapper())) > 0;
//                break;
            default:
                return 0;
        }
        if (!handleRes) {
            return 0;
        }
        return recycleBinMapper.deleteById(recycleId);
    }

    @Override
    public int removeByIds(Collection<?> ids) {
        return recycleBinMapper.deleteBatchIds(ids);
    }

    private <T extends IBaseEntity<?>> int handleProcess(Serializable id, SFunction<T, ?> col, BaseMapper<T> mapper) {
        UpdateWrapper<T> wrapper = new UpdateWrapper<>();
        wrapper.lambda().eq(IBaseEntity::getId, id)
                .set(col, DeleteStatus.NORMAL);
        return mapper.update(null, wrapper);
    }
}
